{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Pandas 字符串重复、链式操作及其他技巧\n",
    "\n",
    "除了之前介绍的分割、替换、查找等常用操作外，Pandas 还提供了一些其他有用的字符串处理功能。本教程将重点介绍字符串的重复、填充，以及如何将多个字符串操作链接起来形成高效的处理流程。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 导入库并准备数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "s = pd.Series(['a', 'b_c', 'd-e-f', '  g  '])\n",
    "print(\"原始 Series:\")\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 字符串重复 `.str.repeat()`\n",
    "\n",
    "`.str.repeat(repeats)` 方法可以将 Series 中的每个字符串重复指定的次数。\n",
    "\n",
    "`repeats` 参数可以是一个整数，也可以是一个与原 Series 长度相同的整数 Series，从而实现对每个元素进行不同次数的重复。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将每个字符串重复3次\n",
    "print(\"重复3次:\")\n",
    "print(s.str.repeat(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 根据一个列表或Series来指定每个元素的重复次数\n",
    "repeats_s = pd.Series([1, 2, 3, 4])\n",
    "print(\"按指定次数重复:\")\n",
    "print(s.str.repeat(repeats=repeats_s))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 字符串填充（Padding）\n",
    "\n",
    "填充操作用于将字符串扩展到指定的宽度，非常适合用于格式化输出。\n",
    "\n",
    "- `.str.pad(width, side='left', fillchar=' ')`: 在指定侧填充字符。`side`可以是 'left', 'right', 或 'both'。\n",
    "- `.str.center(width, fillchar=' ')`: 居中对齐，两侧用字符填充。\n",
    "- `.str.ljust(width, fillchar=' ')`: 左对齐，在右侧填充。\n",
    "- `.str.rjust(width, fillchar=' ')`: 右对齐，在左侧填充。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s_pad = pd.Series(['apple', 'banana', 'cat'])\n",
    "\n",
    "# 将所有字符串填充到宽度为10，左侧用'-'填充\n",
    "print(\"左侧填充:\")\n",
    "print(s_pad.str.pad(width=10, side='left', fillchar='-'))\n",
    "\n",
    "# 居中对齐，宽度为10\n",
    "print(\"\n",
    "居中对齐:\")\n",
    "print(s_pad.str.center(width=10, fillchar='='))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 链式操作 (Chaining Operations)\n",
    "\n",
    "Pandas 的 `.str` 访问器最强大的功能之一就是可以进行链式调用。这意味着你可以将多个字符串处理步骤连接在一行代码中，使代码更简洁、更易读。\n",
    "\n",
    "例如，要清理一个字符串列，你可能需要：\n",
    "1. 去除首尾的空格 (`.str.strip()`)。\n",
    "2. 转换为小写 (`.str.lower()`)。\n",
    "3. 将空格替换为下划线 (`.str.replace()`)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "messy_s = pd.Series(['  Apple Pie  ', 'Banana Split ', '  CHOCOLATE CAKE '])\n",
    "\n",
    "# 不使用链式操作\n",
    "s1 = messy_s.str.strip()\n",
    "s2 = s1.str.lower()\n",
    "s3 = s2.str.replace(' ', '_')\n",
    "print(\"分步操作结果:\")\n",
    "print(s3)\n",
    "\n",
    "# 使用链式操作\n",
    "clean_s = messy_s.str.strip().str.lower().str.replace(' ', '_')\n",
    "print(\"\n",
    "链式操作结果:\")\n",
    "print(clean_s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. 性能优势：矢量化 vs. `.apply`\n",
    "\n",
    "Pandas 的 `.str` 方法是**矢量化**的，这意味着它们在底层使用优化的 C 或 Cython 代码对整个 Series 进行操作，速度远快于使用 `.apply()` 结合 Python 的 lambda 函数。\n",
    "\n",
    "**始终优先使用内置的 `.str` 方法，而不是 `.apply()` 来处理字符串。**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个大数据集来比较性能\n",
    "large_s = pd.Series(['  String {}  '.format(i) for i in range(100000)])\n",
    "\n",
    "print(\"使用 .str.strip() 的时间:\")\n",
    "%timeit large_s.str.strip()\n",
    "\n",
    "print(\"\n",
    "使用 .apply(lambda x: x.strip()) 的时间:\")\n",
    "%timeit large_s.apply(lambda x: x.strip())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. 另一个实用方法：`.str.get_dummies()`\n",
    "\n",
    "在机器学习的特征工程中，我们经常需要将分类变量转换为数值格式。如果一个字符串列中包含由特定分隔符隔开的多个标签，`.str.get_dummies()` 可以一步到位地完成独热编码 (One-Hot Encoding)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dummy_s = pd.Series(['cat|dog', 'cat', 'dog|mouse', 'cat|mouse'])\n",
    "\n",
    "# 使用'|'作为分隔符，生成独热编码的DataFrame\n",
    "dummies_df = dummy_s.str.get_dummies(sep='|')\n",
    "print(dummies_df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. 总结\n",
    "\n",
    "- 使用 `.str.repeat()` 进行字符串重复。\n",
    "- 使用 `.str.pad()`, `.str.center()` 等方法进行格式化填充。\n",
    "- **链式调用**是组合多个字符串操作的最高效、最简洁的方式。\n",
    "- 始终优先选择矢量化的 `.str` 方法，以获得最佳性能。\n",
    "- `.str.get_dummies()` 是处理多标签分类特征的强大工具。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
